﻿using System;
using System.Configuration;
using System.Reflection;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
//Gallio and MbUnit Framework
//using Gallio.Framework;
//using Gallio.Model;
//using MbUnit.Framework;
//MoQ Framework
//using Moq;
//using Subtext.TestLibrary;
using MockingBird.Common.Infrastructure.Helpers;
using MockingBird.Simulator.Interceptors.Wcf.Contracts;
namespace MockingBird.Simulator.Interceptors.Wcf.SimulatorService.Tests
{
    [TestClass]
    public class SimulatorServiceTests
    {
        private static ServiceHost _serviceHost;
        private static int loopCount = 100;
        private static int threadCount = 2 * loopCount;
        private static int waitTimeMs = 300000;
        private static string testEndpointsSourceFolder;
        private static string testEndpointsDestinationFolder;
        internal const string Action1 = "urn:mockingbird.simulator.interceptors.wcf.simulatorservice:action1";
        internal const string Action2 = "urn:mockingbird.simulator.interceptors.wcf.simulatorservice:action2";

        [ClassInitialize]
        public static void SetUpSimulatorServiceTests(TestContext tc)
        {
            CopyEndpointFolders();
            _serviceHost = new ServiceHost(typeof(SimulatorService));
            _serviceHost.Open();
        }

        private static void CopyEndpointFolders()
        {
            testEndpointsSourceFolder = ConfigurationManager.AppSettings["test_endpoints_source_folder"];
            testEndpointsDestinationFolder = ConfigurationManager.AppSettings["test_endpoints_destination_folder"];

            string[] testfolders = Directory.GetDirectories(testEndpointsSourceFolder, "I*");
            DirectoryHelper.CopyFolders(testfolders, testEndpointsDestinationFolder);

        }

        [ClassCleanup]
        public static void TearDownSimulatorServiceTests()
        {
            _serviceHost.Close();
            DeleteEndpointFolders();
        }

        private static void DeleteEndpointFolders()
        {
            DirectoryHelper.RemoveAll(testEndpointsDestinationFolder, "I*");

        }

        #region "Async one way"
        [TestMethod]
        public void TestIOneWayAsync()
        {
            ChannelFactory<IOneWayAsyncChannel> cf = new ChannelFactory<IOneWayAsyncChannel>("IOneWayAsync");
            IOneWayAsyncChannel channel = cf.CreateChannel();
            _testIOneWayAsyncCallbackCount = 0;
            for (int i = 0; i < loopCount; ++i)
            {
                Message request1 = Message.CreateMessage(MessageVersion.Soap11, Action1, new DummyMessage("Action1", "IOneWayAsync"));
                Message request2 = Message.CreateMessage(MessageVersion.Soap11, Action2, new DummyMessage("Action2", "IOneWayAsync"));
                IAsyncResult asyncResult = channel.BeginProcessMessage(request1, this.TestIOneWayAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestIOneWayAsyncCallback(asyncResult);
                }
                asyncResult = channel.BeginProcessMessage(request2, this.TestIOneWayAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestIOneWayAsyncCallback(asyncResult);
                }
            }
            _mreIOneWayAsyncCallback.WaitOne(waitTimeMs);
            Assert.AreEqual<int>(threadCount, _testIOneWayAsyncCallbackCount, "Incorrect number of callbacks");
        }
        ManualResetEvent _mreIOneWayAsyncCallback = new ManualResetEvent(false);
        private int _testIOneWayAsyncCallbackCount = 0;
        private void TestIOneWayAsyncCallback(IAsyncResult asyncResult)
        {
            IOneWayAsyncChannel channel = asyncResult.AsyncState as IOneWayAsyncChannel;
            channel.EndProcessMessage(asyncResult);
            Interlocked.Increment(ref _testIOneWayAsyncCallbackCount);
            if (_testIOneWayAsyncCallbackCount >= threadCount)
            {
                _mreIOneWayAsyncCallback.Set();
            }
        }

        [TestMethod]
        public void TestIOneWayDuplexAsync()
        {
            DuplexCallbackHandler handler = new DuplexCallbackHandler(null);
            InstanceContext instanceContext = new InstanceContext(handler);
            DuplexChannelFactory<IOneWayDuplexAsyncChannel> factory = new DuplexChannelFactory<IOneWayDuplexAsyncChannel>(instanceContext, "IOneWayDuplexAsync");
            IOneWayDuplexAsyncChannel channel = factory.CreateChannel();
            _testIOneWayDuplexAsyncCallbackCount = 0;
            for (int i = 0; i < loopCount; ++i)
            {
                Message request1 = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, Action1, new DummyMessage("Action1", "IOneWayAsync"));
                Message request2 = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, Action2, new DummyMessage("Action1", "IOneWayAsync"));
                IAsyncResult asyncResult = channel.BeginProcessMessage(request1, this.TestIOneWayDuplexAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestIOneWayDuplexAsyncCallback(asyncResult);
                }
                asyncResult = channel.BeginProcessMessage(request2, this.TestIOneWayDuplexAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestIOneWayDuplexAsyncCallback(asyncResult);
                }
            }
            _mreIOneWayDuplexAsyncCallback.WaitOne(waitTimeMs);
            Assert.AreEqual<int>(threadCount, _testIOneWayDuplexAsyncCallbackCount, "Incorrect number of callbacks");
        }
        ManualResetEvent _mreIOneWayDuplexAsyncCallback = new ManualResetEvent(false);
        private int _testIOneWayDuplexAsyncCallbackCount = 0;
        private void TestIOneWayDuplexAsyncCallback(IAsyncResult asyncResult)
        {
            IOneWayDuplexAsyncChannel channel = asyncResult.AsyncState as IOneWayDuplexAsyncChannel;
            channel.EndProcessMessage(asyncResult);
            Interlocked.Increment(ref _testIOneWayDuplexAsyncCallbackCount);
            if (_testIOneWayDuplexAsyncCallbackCount >= threadCount)
            {
                _mreIOneWayDuplexAsyncCallback.Set();
            }
        }

        [TestMethod]
        public void TestIOneWaySessionAsync()
        {
            ChannelFactory<IOneWaySessionAsync> cf = new ChannelFactory<IOneWaySessionAsync>("IOneWaySessionAsync");
            IOneWaySessionAsync channel = cf.CreateChannel();
            _testIOneWaySessionAsyncCallbackCount = 0;
            for (int i = 0; i < loopCount; ++i)
            {
                Message request1 = Message.CreateMessage(MessageVersion.Default, Action1, new DummyMessage("Action1", "IOneWaySessionAsync"));
                Message request2 = Message.CreateMessage(MessageVersion.Default, Action2, new DummyMessage("Action1", "IOneWaySessionAsync"));
                IAsyncResult asyncResult = channel.BeginProcessMessage(request1, this.TestIOneWaySessionAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestIOneWaySessionAsyncCallback(asyncResult);
                }
                asyncResult = channel.BeginProcessMessage(request2, this.TestIOneWaySessionAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestIOneWaySessionAsyncCallback(asyncResult);
                }
            }
            _mreIOneWaySessionAsyncCallback.WaitOne(waitTimeMs);
            Assert.AreEqual<int>(threadCount, _testIOneWaySessionAsyncCallbackCount, "Incorrect number of callbacks");
        }
        ManualResetEvent _mreIOneWaySessionAsyncCallback = new ManualResetEvent(false);
        private int _testIOneWaySessionAsyncCallbackCount = 0;
        private void TestIOneWaySessionAsyncCallback(IAsyncResult asyncResult)
        {
            Interlocked.Increment(ref _testIOneWaySessionAsyncCallbackCount);
            if (_testIOneWaySessionAsyncCallbackCount >= threadCount)
            {
                _mreIOneWaySessionAsyncCallback.Set();
            }
        }
        #endregion

        #region "Async - 2 way"
        [TestMethod]
        public void TestITwoWayAsync()
        {
            ChannelFactory<ITwoWayAsyncChannel> cf = new ChannelFactory<ITwoWayAsyncChannel>("ITwoWayAsync");
            ITwoWayAsyncChannel channel = cf.CreateChannel();
            _testITwoWayAsyncCallbackCount = 0;
            for (int i = 0; i < loopCount; ++i)
            {
                Message request1 = Message.CreateMessage(MessageVersion.Soap11, Action1, new DummyMessage("Action1", "ITwoWayAsync"));
                Message request2 = Message.CreateMessage(MessageVersion.Soap11, Action2, new DummyMessage("Action2", "ITwoWayAsync"));
                IAsyncResult asyncResult = channel.BeginProcessMessage(request1, this.TestITwoWayAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestITwoWayAsyncCallback(asyncResult);
                }
                asyncResult = channel.BeginProcessMessage(request2, this.TestITwoWayAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestITwoWayAsyncCallback(asyncResult);
                }
            }
            _mreITwoWayAsyncCallback.WaitOne(waitTimeMs);
            Assert.AreEqual<int>(threadCount, _testITwoWayAsyncCallbackCount, "Incorrect number of callbacks");
        }
        ManualResetEvent _mreITwoWayAsyncCallback = new ManualResetEvent(false);
        private int _testITwoWayAsyncCallbackCount = 0;
        private void TestITwoWayAsyncCallback(IAsyncResult asyncResult)
        {
            ITwoWayAsyncChannel channel = asyncResult.AsyncState as ITwoWayAsyncChannel;
            channel.EndProcessMessage(asyncResult);
            Interlocked.Increment(ref _testITwoWayAsyncCallbackCount);
            if (_testITwoWayAsyncCallbackCount >= threadCount)
            {
                _mreITwoWayAsyncCallback.Set();
            }
        }

        [TestMethod]
        public void TestITwoWayVoidAsync()
        {
            ChannelFactory<ITwoWayVoidAsyncChannel> cf = new ChannelFactory<ITwoWayVoidAsyncChannel>("ITwoWayVoidAsync");
            ITwoWayVoidAsyncChannel channel = cf.CreateChannel();
            _testITwoWayVoidAsyncCallbackCount = 0;
            for (int i = 0; i < loopCount; ++i)
            {
                Message request1 = Message.CreateMessage(MessageVersion.Soap11, Action1, new DummyMessage("Action1", "ITwoWayVoidAsync"));
                Message request2 = Message.CreateMessage(MessageVersion.Soap11, Action2, new DummyMessage("Action2", "ITwoWayVoidAsync"));
                IAsyncResult asyncResult = channel.BeginProcessMessage(request1, this.TestITwoWayVoidAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestITwoWayVoidAsyncCallback(asyncResult);
                }
                asyncResult = channel.BeginProcessMessage(request2, this.TestITwoWayVoidAsyncCallback, channel);
                if (asyncResult.CompletedSynchronously)
                {
                    TestITwoWayVoidAsyncCallback(asyncResult);
                }
            }
            _mreITwoWayVoidAsyncCallback.WaitOne(waitTimeMs);
            Assert.AreEqual<int>(threadCount, _testITwoWayVoidAsyncCallbackCount, "Incorrect number of callbacks");
        }
        ManualResetEvent _mreITwoWayVoidAsyncCallback = new ManualResetEvent(false);
        private int _testITwoWayVoidAsyncCallbackCount = 0;
        private void TestITwoWayVoidAsyncCallback(IAsyncResult asyncResult)
        {
            ITwoWayVoidAsyncChannel channel = asyncResult.AsyncState as ITwoWayVoidAsyncChannel;
            channel.EndProcessMessage(asyncResult);
            Interlocked.Increment(ref _testITwoWayVoidAsyncCallbackCount);
            if (_testITwoWayVoidAsyncCallbackCount >= threadCount)
            {
                _mreITwoWayVoidAsyncCallback.Set();
            }
        }
        #endregion End Async2way

        #region "sync -oneway"
        [TestMethod]
        public void TestIOneWay()
        {
            ChannelFactory<IOneWayChannel> cf = new ChannelFactory<IOneWayChannel>("IOneWay");
            IOneWayChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Soap11, Action1, new DummyMessage("Action1", "IOneWay"));
            Message request2 = Message.CreateMessage(MessageVersion.Soap11, Action2, new DummyMessage("Action2", "IOneWay"));
            channel.ProcessMessage(request1);
            channel.ProcessMessage(request2);
        }

        [TestMethod]
        public void TestIOneWaySession()
        {
            ChannelFactory<IOneWaySessionChannel> cf = new ChannelFactory<IOneWaySessionChannel>("IOneWaySession");
            IOneWaySessionChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Default, Action1, new DummyMessage("Action1", "IOneWaySession"));
            Message request2 = Message.CreateMessage(MessageVersion.Default, Action2, new DummyMessage("Action2", "IOneWaySession"));
            channel.ProcessMessage(request1);
            channel.ProcessMessage(request2);
        }

        [TestMethod]
        public void TestIOneWayDuplex()
        {
            DuplexCallbackHandler handler = new DuplexCallbackHandler("Action1");
            InstanceContext instanceContext = new InstanceContext(handler);
            ChannelFactory<IOneWayDuplexChannel> cf = new DuplexChannelFactory<IOneWayDuplexChannel>(instanceContext, "IOneWayDuplex");
            IOneWayDuplexChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, Action1, new DummyMessage("Action1", "IOneWayDuplex"));
            channel.ProcessMessage(request1);
            handler.ReceivedEvent.WaitOne(waitTimeMs);
            handler.ActionToVerify = "Action2";
            Message request2 = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, Action2, new DummyMessage("Action2", "IOneWayDuplex"));
            channel.ProcessMessage(request2);
            handler.ReceivedEvent.WaitOne(waitTimeMs);
        }
        #endregion

        #region "sync - 2 way"
        [TestMethod]
        public void TestITwoWay()
        {
            ChannelFactory<ITwoWayChannel> cf = new ChannelFactory<ITwoWayChannel>("ITwoWay");
            ITwoWayChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Soap11, Action1, new DummyMessage("Action1", "ITwoWay"));
            Message response1 = channel.ProcessMessage(request1);
            DummyMessage dm = response1.GetBody<DummyMessage>();
            Assert.AreEqual<string>("Action1", dm.Action, "Incorrect DummyMessage.Action");
            Message request2 = Message.CreateMessage(MessageVersion.Soap11, Action2, new DummyMessage("Action2", "ITwoWay"));
            Message response2 = channel.ProcessMessage(request2);
            dm = response2.GetBody<DummyMessage>();
            Assert.AreEqual<string>("Action2", dm.Action, "Incorrect DummyMessage.Action");
        }

        [TestMethod]
        public void TestITwoWay_netNamedPipe()
        {
            ChannelFactory<ITwoWayChannel> cf = new ChannelFactory<ITwoWayChannel>("ITwoWay_netNamedPipe");
            ITwoWayChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Default, Action1, new DummyMessage("Action1", "ITwoWay_netNamedPipe"));
            Message response1 = channel.ProcessMessage(request1);
            DummyMessage dm = response1.GetBody<DummyMessage>();
            Assert.AreEqual<string>("Action1", dm.Action, "Incorrect DummyMessage.Action");
            Message request2 = Message.CreateMessage(MessageVersion.Default, Action2, new DummyMessage("Action2", "ITwoWay_netNamedPipe"));
            Message response2 = channel.ProcessMessage(request2);
            dm = response2.GetBody<DummyMessage>();
            Assert.AreEqual<string>("Action2", dm.Action, "Incorrect DummyMessage.Action");
        }

        [TestMethod]
        public void TestITwoWay_netTcp()
        {
            ChannelFactory<ITwoWayChannel> cf = new ChannelFactory<ITwoWayChannel>("ITwoWay_netTcp");
            ITwoWayChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Default, Action1, new DummyMessage("Action1", "ITwoWay_netTcp"));
            Message response1 = channel.ProcessMessage(request1);
            DummyMessage dm = response1.GetBody<DummyMessage>();
            Assert.AreEqual<string>("Action1", dm.Action, "Incorrect DummyMessage.Action");
            Message request2 = Message.CreateMessage(MessageVersion.Default, Action2, new DummyMessage("Action2", "ITwoWay_netTcp"));
            Message response2 = channel.ProcessMessage(request2);
            dm = response2.GetBody<DummyMessage>();
            Assert.AreEqual<string>("Action2", dm.Action, "Incorrect DummyMessage.Action");
        }

        [TestMethod]
        public void TestITwoWayVoid()
        {
            ChannelFactory<ITwoWayVoidChannel> cf = new ChannelFactory<ITwoWayVoidChannel>("ITwoWayVoid");
            ITwoWayVoidChannel channel = cf.CreateChannel();
            Message request1 = Message.CreateMessage(MessageVersion.Soap11, Action1, new DummyMessage("Action1", "ITwoWayVoid"));
            Message request2 = Message.CreateMessage(MessageVersion.Soap11, Action2, new DummyMessage("Action2", "ITwoWayVoid"));
            channel.ProcessMessage(request1);
            channel.ProcessMessage(request2);
        }
        #endregion
    }
}
